﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace AESyouhua
{
    class Encryption
    {
        public static int[,] ciphertext;
        public static int[,] key;
        public static int[,] plain;
        public static int[,] Getencryption(string str, int[,] _key)
        {
            key = _key;
            int length = str.Length;
            for (int i = 0; i < 16 - length % 16; i++)
            {
                str += " ";
            }

            byte[] buf = Encoding.Default.GetBytes(str.ToString());
            int[] cipherkey = new int[16];//秘钥
            plain = new int[buf.Length / 16, 16];
            ciphertext = new int[buf.Length / 16, 16];
            int[] plaintext = new int[16];

            for (int i = 1; i <= plain.GetLength(0); i++)
            {
                for (int j = 1; j <= 16; j++)
                {
                    plain[i - 1, j - 1] = buf[(j - 1) + 16 * (i - 1)];
                }
            }
            if( plain.GetLength(0) >= 4)
            {
                int index = plain.GetLength(0);
                List<Task> taskList = new List<Task>();// 准备一个task集合
                TaskFactory taskFactory = new TaskFactory();//创建一个task工厂
                for (int i = 0; i < index; i = i + 4)
                {
                    ///////////////////////////////////////////////////////////////
                    int s = i;
                    Action act = () => fenzuState(s);
                    Task task = taskFactory.StartNew(act);//启动线程  开启一个task
                    taskList.Add(task);

                    if (s + 1 < index)
                    {
                        Action act1 = () => fenzuState(s + 1);
                        Task task1 = taskFactory.StartNew(act1);//启动线程  开启一个task
                        taskList.Add(task1);
                        if (s + 2 < index)
                        {
                            Action act2 = () => fenzuState(s + 2);
                            Task task2 = taskFactory.StartNew(act2);//启动线程  开启一个task
                            taskList.Add(task2);
                            if (s + 3 < index)
                            {
                                Action act3 = () => fenzuState(s + 3);
                                Task task3 = taskFactory.StartNew(act3);//启动线程  开启一个task
                                taskList.Add(task3);
                            }
                            else
                            {
                                break;
                            }
                            
                        }
                        else
                        {
                            break;
                        }                    
                    }
                    else
                    {
                        break;
                    }                   

                    if (taskList.Count > 4)
                    {
                        Task.WaitAny(taskList.ToArray());
                        taskList = taskList.Where(t => t.Status == TaskStatus.Running).ToList();
                    }
                }
                Task.WaitAll(taskList.ToArray());
            }
            else
            {
                OneState();
            }
            
            return ciphertext;
        }

        public static object plus_lock = new object();

        public static void OneState()
        {
            int[] cipherkey = new int[16];
            int[] plaintext = new int[16];
            for (int i = 0; i < plain.GetLength(0); i++)
            {
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[0, h];
                    plaintext[h] = plain[i, h];
                }

                plaintext = AddRoundKey(plaintext, cipherkey);
                ;
                for (int j = 0; j < key.GetLength(0) - 2; j++)
                {
                    for (int h = 0; h < 16; h++)
                    {
                        cipherkey[h] = key[j + 1, h];
                    }
                    for (int h = 0; h < plaintext.Length; h++)
                    {
                        plaintext[h] = SubBytes.GetSubByte(plaintext[h]);
                    }

                    plaintext = ShiftRows(plaintext);

                    plaintext = MixColumn.GetMixColumn(plaintext);

                    plaintext = AddRoundKey(plaintext, cipherkey);

                }
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[key.GetLength(0) - 1, h];
                }
                for (int h = 0; h < plaintext.Length; h++)
                {
                    plaintext[h] = SubBytes.GetSubByte(plaintext[h]);
                }
                plaintext = ShiftRows(plaintext);
                plaintext = AddRoundKey(plaintext, cipherkey);

                for (int j = 0; j < 16; j++)
                    ciphertext[i, j] = plaintext[j];
            }
        }



        public static void fenzuState(int i)
        {
            int[] plaintext = new int[16];
            int[] cipherkey = new int[16];//秘钥
            for (int h = 0; h < 16; h++)
            {
                cipherkey[h] = key[0, h];
                plaintext[h] = plain[i, h];
                plaintext[h] ^= key[0, h];//AddRoundKey与秘钥异或
            }
            for (int j = 0; j < key.GetLength(0) - 2; j++)
            {
                for (int h = 0; h < 16; h++)
                {
                    cipherkey[h] = key[j + 1, h];
                }
                for (int h = 0; h < plaintext.Length; h++)
                {
                    plaintext[h] = SubBytes.GetSubByte(plaintext[h]);
                }

                plaintext = ShiftRows(plaintext);

                plaintext = MixColumn.GetMixColumn(plaintext);

                plaintext = AddRoundKey(plaintext, cipherkey);

            }
            for (int h = 0; h < 16; h++)
            {
                cipherkey[h] = key[key.GetLength(0) - 1, h];
            }
            for (int h = 0; h < plaintext.Length; h++)
            {
                plaintext[h] = SubBytes.GetSubByte(plaintext[h]);
            }
            plaintext = ShiftRows(plaintext);
            plaintext = AddRoundKey(plaintext, cipherkey);

            lock (plus_lock)
            {
                for (int j = 0; j < 16; j++)
                    ciphertext[i, j] = plaintext[j];
            }

        }

        public static int[] AddRoundKey(int[] cipher, int[] key)
        {
            for (int i = 0; i < 16; i++)
            {
                cipher[i] ^= key[i];
            }
            return cipher;
        }
        public static int[] ShiftRows(int[] cipher)
        {
            int[] cipherX = new int[16];

            for (int i = 0; i < 16; i++)
            {
                if (i % 4 == 0)
                    cipherX[i] = cipher[i];
                if (i % 4 == 1)
                    cipherX[i] = cipher[(i + 4) % 16];
                if (i % 4 == 2)
                    cipherX[i] = cipher[(i + 8) % 16];
                if (i % 4 == 3)
                    cipherX[i] = cipher[(i + 12) % 16];
            }
            return cipherX;
        }


    }
}
